// -*- C++ -*------------------------------------------------------------------
// $Id: PdbSaver.cc,v 1.6 2007-10-26 14:55:16 biocomp Exp $
//
//  Class:             PdbSaver
//
//  Base Class(es):    Saver
//
//  Derived Class(es): -
//
//  Containing:        -
//
//  Author:            Silvio Tosatto
//
//  Project Name:      Victor
//
//  Date:              08/99
//
//  Reviewed By:       <Name>
//
//  Description:
//     Saves components (Atoms, Groups, etc.) in XYZ (carthesian coord) format.
//
// ---------------------------------------------------------------------------

// Includes:
#include <PdbSaver.h>
#include <IoTools.h>
#include <vector3.h>

// Global constants, typedefs, etc. (to avoid):

using namespace Biopool;


// CONSTRUCTORS/DESTRUCTOR:


// MODIFIERS:

// -*- C++ -*-----------------------------------------------------------------
//
//  Method:        PdbSaver::saveGroup
//
//  Author:        Silvio Tosatto 
//
//  Date:          09/99
//
//  Description:
//    Saves a group in PDB format. 
//
// ----------------------------------------------------------------------------
void 
PdbSaver::saveGroup(Group& gr)
{
  gr.sync();

  for (unsigned int i = 0; i < gr.size(); i++)
    {
      string atName = gr[i].getType();

      if (atName == "OXT")  // cosmetics: OXT has to be output after 
	continue;           // the sidechain and therefore goes in saveSpacer

      if (!isdigit(atName[0]))
	atName = ' ' + atName;
      while (atName.size() < 4)
	atName += ' ';
      output << "ATOM" << setw(7) << gr[i].getNumber() << " " << atName
	     << " " 
	     << gr.getType() << setw(6) << aminoOffset << "    "  
	     << setw(8) << setprecision(3) << gr[i].getCoords().x 
	     << setw(8) << setprecision(3) << gr[i].getCoords().y 
	     << setw(8) << setprecision(3) << gr[i].getCoords().z 
	     << "  1.00" << setw(6) << setprecision(2) << gr[i].getBFac()
	     << "          "  << atName[1] << "\n";

      atomOffset =  gr[i].getNumber()+1;
    }

  aminoOffset++;
}

// -*- C++ -*-----------------------------------------------------------------
//
//  Method:        PdbSaver::saveSideChain
//
//  Author:        Silvio Tosatto 
//
//  Date:          09/99
//
//  Description:
//    Saves a sidechain in PDB format. 
//
// ----------------------------------------------------------------------------
void 
PdbSaver::saveSideChain(SideChain& sc)
{
  saveGroup(sc);
}

// -*- C++ -*-----------------------------------------------------------------
//
//  Method:        PdbSaver::saveAminoAcid
//
//  Author:        Silvio Tosatto 
//
//  Date:          09/99
//
//  Description:
//    Saves an aminoacid in PDB format. 
//
// ----------------------------------------------------------------------------
void 
PdbSaver::saveAminoAcid(AminoAcid& aa)
{
  saveGroup(aa);
}


// -*- C++ -*-----------------------------------------------------------------
//
//  Method:        PdbSaver::saveSpacer
//
//  Author:        Silvio Tosatto 
//
//  Date:          09/99
//
//  Description:
//    Saves a spacer in PDB format. 
//
// ----------------------------------------------------------------------------
void 
PdbSaver::saveSpacer(Spacer& sp)
{
  PRINT_NAME;
  unsigned int oldPrec = output.precision();
  ios::fmtflags oldFlags = output.flags();
  output.setf(ios::fixed, ios::floatfield);

  if (sp.getDepth() == 0)
    {
      if (writeTer)
	output << "HEADER    " << sp.getType() << "\n"
	    << "REMARK    created using Biopool2000 $Revision: 1.6 $ \n";
      aminoOffset = 0;
      atomOffset = sp.getAtomStartOffset();
    }

  if (writeSeq)
    writeSeqRes(sp);
  if (writeSecStr)
    writeSecondary(sp);

  for (unsigned int i = 0; i < sp.sizeAmino(); i++)
    {
      while ( (sp.isGap(aminoOffset)) 
	      && (aminoOffset < sp.maxPdbNumber()) )
	aminoOffset++;

      sp.getAmino(i).save(*this);
    }

  if (sp.getAmino(sp.sizeAmino()-1).isMember(OXT))
    {  // cosmetics: write OXT after last side chain
      unsigned int index = sp.sizeAmino()-1;
      output << "ATOM" << setw(7) << sp.getAmino(index)[OXT].getNumber() 
	     << "  OXT " 
	     << sp.getAmino(index).getType() << setw(6) << aminoOffset-1 
	     << "    " << setw(8) << setprecision(3) 
	     << sp.getAmino(index)[OXT].getCoords().x 
	     << setw(8) << setprecision(3) 
	     << sp.getAmino(index)[OXT].getCoords().y 
	     << setw(8) << setprecision(3) 
	     << sp.getAmino(index)[OXT].getCoords().z 
	     << "  1.00" << setw(6) << setprecision(2) 
	     << sp.getAmino(index)[OXT].getBFac() << "          O\n";
    }

  if ((sp.getDepth() == 0) && (writeTer))
    output << "TER    " << setw(4) << atomOffset+1 << "      " 
	   << sp.getAmino(sp.sizeAmino()-1).getType() << "  " 
	   << setw(4) << aminoOffset-1 << "\n";

  output.precision(oldPrec);
  output.flags(oldFlags);
}


// -*- C++ -*-----------------------------------------------------------------
//
//  Method:        PdbSaver::saveLigand
//
//  Author:        Silvio Tosatto
//
//  Date:          02/02
//
//  Description:
//    Saves a Ligand in PDB format. 
//
// ----------------------------------------------------------------------------
void 
PdbSaver::saveLigand(Ligand& gr)
{
  ligandOffset++;
  gr.sync();
  unsigned int oldPrec = output.precision();
  ios::fmtflags oldFlags = output.flags();
  output.setf(ios::fixed, ios::floatfield);

  for (unsigned int i = 0; i < gr.size(); i++)
    {
      string atName = gr[i].getType();
      if (atName.size() < 4)
	atName = ' ' + atName;
      while (atName.size() < 4)
	atName += ' ';
      output << "HETATM" << setw(5) << ++atomOffset << " " << atName
	     << " ";

      for (unsigned j = gr.getType().length(); j < 3; j++)
	  output << " ";

      output << gr.getType() << setw(6) << ligandOffset << "    "  
	     << setw(8) << setprecision(3) << gr[i].getCoords().x 
	     << setw(8) << setprecision(3) << gr[i].getCoords().y 
	     << setw(8) << setprecision(3) << gr[i].getCoords().z 
	     << "  1.00" << setw(6) << setprecision(2) << gr[i].getBFac()
	     << "\n";
    }

  output.precision(oldPrec);
  output.flags(oldFlags);
}

// -*- C++ -*-----------------------------------------------------------------
//
//  Method:        PdbSaver::saveLigandSet
//
//  Author:        Silvio Tosatto
//
//  Date:          02/02
//
//  Description:
//    Saves a LigandSet in PDB format. 
//
// ----------------------------------------------------------------------------
void 
PdbSaver::saveLigandSet(LigandSet& ls)
{
  ligandOffset = 0;

  for (unsigned int i = 0; i < ls.sizeLigand(); i++)
      ls[i].save(*this);
}

// -*- C++ -*-----------------------------------------------------------------
//
//  Method:        PdbSaver::writeSeqRes
//
//  Author:        Silvio Tosatto 
//
//  Date:          05/00
//
//  Description:
//    Writes the SEQRES entry (PDB format) for a spacer.
//
// ----------------------------------------------------------------------------
void 
PdbSaver::writeSeqRes(Spacer& sp)
{
  for (unsigned int i = 0; i < sp.sizeAmino() / 13; i++)
    {
      output << "SEQRES " << setw(3) << i << "   " << setw(3) 
	     << sp.sizeAmino() << "   ";
      for (unsigned int j = 0; j < 13; j++)
	output << sp.getAmino((i * 13) + j).getType() << " ";
      output << "\n";
    }
  if (sp.sizeAmino() % 13 > 0)
    {
      output << "SEQRES " << setw(3) << sp.sizeAmino() / 13 + 1 << "   " 
	     << setw(3) << sp.sizeAmino() << "   ";
      for (unsigned int j = 13 * (sp.sizeAmino() / 13); j < sp.sizeAmino(); j++)
	output << sp.getAmino(j).getType() << " ";
      output << "\n";
    }
}


// -*- C++ -*-----------------------------------------------------------------
//
//  Method:        PdbSaver::writeSecondary
//
//  Author:        Silvio Tosatto 
//
//  Date:          05/00
//
//  Description:
//    Writes the secondary information (PDB format) for a spacer, e.g. HELIX,
//    SHEET, etc.
//
// ----------------------------------------------------------------------------
void 
PdbSaver::writeSecondary(Spacer& sp)
{
//    vector<unsigned int> helix, strand, turn;

//      for (unsigned int i = 0; i < sp.sizeAmino(); i++)
//        switch sp.getAmino(i).getState() 
//        {
//        case HELIX :
//  	helix.push_back(i);
//        case STRAND :
//  	strand.push_back(i);
//        case TURN :
//  	turn.push_back(i);
//        case COIL :
//        default: 
//  	continue;
//        }
} 

